"""
推荐服务
实现基于协同过滤的商品推荐算法
"""

from typing import List, Dict, Tuple, Optional
from core.models.product import Product
from core.models.order import Order, OrderStatus
from core.services.data_manager import DataManager
from core.utils.logger import debug, info, warning, error


class RecommendationService:
    """推荐服务类 - 提供商品推荐功能"""
    
    def __init__(self):
        self.data_manager = DataManager()
    
    def recommend_products(self, user_id: Optional[str] = None, limit: int = 5) -> List[Product]:
        """
        为指定用户推荐商品
        
        Args:
            user_id: 用户ID（如果为None，则推荐热门商品）
            limit: 推荐商品数量
            
        Returns:
            List[Product]: 推荐的商品列表
        """
        if user_id and user_id != "guest":
            # 基于用户购买历史推荐
            recommendations = self._recommend_based_on_history(user_id, limit)
            if recommendations:
                debug(f"✅ 为用户 {user_id} 推荐 {len(recommendations)} 个商品")
                return recommendations
        
        # 如果用户没有购买历史，推荐热门商品
        recommendations = self._recommend_popular_products(limit)
        debug(f"✅ 推荐 {len(recommendations)} 个热门商品")
        return recommendations
    
    def _recommend_based_on_history(self, user_id: str, limit: int) -> List[Product]:
        """
        基于用户购买历史推荐商品（协同过滤）
        
        算法思路：
        1. 获取用户购买的商品的类别
        2. 找到购买过相同类别商品的其他用户
        3. 推荐这些用户还购买过的其他商品
        """
        try:
            # 获取用户的所有订单
            from core.services.order_service import OrderService
            order_service = OrderService()
            user_orders = order_service.get_user_orders(user_id)
            
            # 获取用户购买过的商品类别
            user_categories = set()
            purchased_product_ids = set()
            
            for order in user_orders:
                if order.status in [OrderStatus.PAID, OrderStatus.SHIPPED, OrderStatus.COMPLETED]:
                    for item in order.items:
                        user_categories.add(item.product_id)
                        purchased_product_ids.add(item.product_id)
            
            if not user_categories:
                return []
            
            # 获取所有订单
            all_orders = order_service.get_all_orders()
            
            # 找到相似用户（购买过相同类别商品的用户）
            similar_users = []
            for order in all_orders:
                if order.user_id == user_id:
                    continue
                
                # 检查这个用户是否购买过相同的商品类别
                for item in order.items:
                    if item.product_id in user_categories:
                        similar_users.append(order.user_id)
                        break
            
            # 获取相似用户购买的商品
            recommended_product_ids = set()
            for order in all_orders:
                if order.user_id in similar_users:
                    if order.status in [OrderStatus.PAID, OrderStatus.SHIPPED, OrderStatus.COMPLETED]:
                        for item in order.items:
                            if item.product_id not in purchased_product_ids:
                                recommended_product_ids.add(item.product_id)
            
            # 从产品服务获取推荐商品
            if recommended_product_ids:
                from core.services.product_service import ProductService
                product_service = ProductService()
                
                recommended_products = []
                for product_id in list(recommended_product_ids)[:limit]:
                    product = product_service.get_product_by_id(product_id)
                    if product and product.stock > 0:
                        recommended_products.append(product)
                
                return recommended_products
            
            return []
            
        except Exception as e:
            error(f"基于历史推荐失败: {e}")
            return []
    
    def _recommend_popular_products(self, limit: int) -> List[Product]:
        """
        推荐热门商品（基于销量和评分）
        
        算法思路：
        1. 统计每个商品的销量
        2. 计算商品的评分
        3. 综合评分和销量，推荐热门商品
        """
        try:
            from core.services.product_service import ProductService
            from core.services.order_service import OrderService
            from core.services.review_service import ReviewService
            
            product_service = ProductService()
            order_service = OrderService()
            review_service = ReviewService()
            
            # 获取所有商品
            all_products = product_service.get_all_products()
            
            # 获取所有订单
            all_orders = order_service.get_all_orders()
            
            # 统计每个商品的销量
            product_sales = {}
            for order in all_orders:
                if order.status in [OrderStatus.PAID, OrderStatus.SHIPPED, OrderStatus.COMPLETED]:
                    for item in order.items:
                        product_id = item.product_id
                        product_sales[product_id] = product_sales.get(product_id, 0) + item.quantity
            
            # 计算每个商品的综合得分
            product_scores = {}
            
            for product in all_products:
                sales_count = product_sales.get(product.product_id, 0)
                
                # 获取商品评分统计
                rating_stats = product_service.get_product_rating_stats(product.product_id)
                avg_rating = rating_stats.get('average_rating', 0)
                review_count = rating_stats.get('total_reviews', 0)
                
                # 综合得分：销量权重0.4，评分权重0.6
                popularity_score = sales_count * 0.4 + avg_rating * 0.6
                
                # 如果有销量或评论，才加入推荐列表
                if sales_count > 0 or review_count > 0:
                    product_scores[product.product_id] = popularity_score
            
            # 按得分排序
            sorted_products = sorted(product_scores.items(), key=lambda x: x[1], reverse=True)
            
            # 获取前N个商品
            recommended_products = []
            for product_id, score in sorted_products[:limit]:
                product = product_service.get_product_by_id(product_id)
                if product and product.stock > 0:
                    recommended_products.append(product)
            
            # 如果推荐的商品不足，从所有商品中随机补充
            if len(recommended_products) < limit:
                for product in all_products:
                    if product not in recommended_products and product.stock > 0:
                        recommended_products.append(product)
                        if len(recommended_products) >= limit:
                            break
            
            return recommended_products[:limit]
            
        except Exception as e:
            error(f"推荐热门商品失败: {e}")
            return []
    
    def recommend_similar_products(self, product_id: str, limit: int = 5) -> List[Product]:
        """
        推荐相似商品（基于类别）
        
        Args:
            product_id: 当前商品ID
            limit: 推荐数量
            
        Returns:
            List[Product]: 相似商品列表
        """
        try:
            from core.services.product_service import ProductService
            product_service = ProductService()
            
            # 获取当前商品
            current_product = product_service.get_product_by_id(product_id)
            if not current_product:
                return []
            
            # 获取同类别商品
            same_category_products = []
            for product in product_service.get_all_products():
                if (product.product_id != product_id and 
                    product.get_category() == current_product.get_category() and
                    product.stock > 0):
                    same_category_products.append(product)
            
            # 返回同类别商品（最多limit个）
            return same_category_products[:limit]
            
        except Exception as e:
            error(f"推荐相似商品失败: {e}")
            return []
    
    def get_user_purchase_categories(self, user_id: str) -> List[str]:
        """
        获取用户购买过的商品类别
        
        Args:
            user_id: 用户ID
            
        Returns:
            List[str]: 商品类别列表
        """
        try:
            from core.services.order_service import OrderService
            from core.services.product_service import ProductService
            product_service = ProductService()
            order_service = OrderService()
            
            user_orders = order_service.get_user_orders(user_id)
            
            categories = set()
            for order in user_orders:
                if order.status in [OrderStatus.PAID, OrderStatus.SHIPPED, OrderStatus.COMPLETED]:
                    for item in order.items:
                        product = product_service.get_product_by_id(item.product_id)
                        if product:
                            categories.add(product.get_category())
            
            return list(categories)
            
        except Exception as e:
            error(f"获取用户购买类别失败: {e}")
            return []
    
    def recommend_for_order(self, order: Order, limit: int = 3) -> List[Product]:
        """
        基于订单推荐相关商品
        
        算法思路：
        1. 获取订单中所有商品的类别
        2. 找出这些类别的其他商品
        3. 按评分和销量排序
        4. 过滤掉订单中已购买的商品
        5. 返回前limit个
        
        Args:
            order: 订单对象
            limit: 推荐数量
            
        Returns:
            List[Product]: 推荐的商品列表
        """
        try:
            from core.services.product_service import ProductService
            from core.services.order_service import OrderService
            
            product_service = ProductService()
            order_service = OrderService()
            
            # 1. 获取订单中所有商品的类别和ID
            order_categories = set()
            order_product_ids = set()
            
            for item in order.items:
                order_product_ids.add(item.product_id)
                product = product_service.get_product_by_id(item.product_id)
                if product:
                    order_categories.add(product.get_category())
            
            if not order_categories:
                debug("订单中没有有效商品")
                return []
            
            # 2. 获取所有订单统计销量
            all_orders = order_service.get_all_orders()
            product_sales = {}
            for o in all_orders:
                if o.status in [OrderStatus.PAID, OrderStatus.SHIPPED, OrderStatus.COMPLETED]:
                    for order_item in o.items:
                        product_id = order_item.product_id
                        product_sales[product_id] = product_sales.get(product_id, 0) + order_item.quantity
            
            # 3. 找出符合条件的商品（同类且有库存）
            candidate_products = []
            for product in product_service.get_all_products():
                # 跳过订单中已有的商品
                if product.product_id in order_product_ids:
                    continue
                
                # 只考虑同类别的商品
                if product.get_category() in order_categories:
                    # 只考虑有库存的商品
                    if product.stock > 0:
                        candidate_products.append(product)
            
            if not candidate_products:
                debug("没有找到符合条件的推荐商品")
                return []
            
            # 4. 对候选商品进行评分和排序
            product_scores = []
            for product in candidate_products:
                # 获取销量
                sales_count = product_sales.get(product.product_id, 0)
                
                # 获取商品评分
                rating_stats = product_service.get_product_rating_stats(product.product_id)
                avg_rating = rating_stats.get('average_rating', 0)
                
                # 综合得分：销量权重0.3，评分权重0.7
                score = sales_count * 0.3 + avg_rating * 0.7
                
                product_scores.append((product, score))
            
            # 按得分排序
            product_scores.sort(key=lambda x: x[1], reverse=True)
            
            # 5. 返回前limit个
            recommended_products = [product for product, score in product_scores[:limit]]
            
            debug(f"为订单推荐了 {len(recommended_products)} 个商品")
            return recommended_products
            
        except Exception as e:
            error(f"基于订单推荐失败: {e}")
            return []

